﻿// ----------------------------------------------------------------------------------
// Sample Code from Fernando Machado Píriz's blog: http://fernandomachadopiriz.com
//
// <copyright company="Fernando Machado Píriz" file="CloseProgramsModel.cs">
// Copyright (c) Fernando Machado Píriz. Distributed under FSF's GPL v2.</copyright>
// ----------------------------------------------------------------------------------
// This code and information are provided "as is" without warranty of any kind,
// either expressed of implied, including but not limited to the implied warranties
// of merchantability and/or fitness for a particular purpose.
// ----------------------------------------------------------------------------------
namespace ClosePrograms
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Reflection;
    using System.Text;
    using GivingAPresentation.Commons;
    
    /// <summary>
    /// The model of the <code>CloseProgramsView</code> using the Model View View Model pattern.
    /// </summary>
    public class CloseProgramsModel : BaseModel
    {
        /// <summary>
        /// The name of the setting exposed in this user control.
        /// </summary>
        private const string CloseTheseProgramsSettingName = "CloseThesePrograms";

        /// <summary>
        /// The name of the setting exposed in this user control.
        /// </summary>
        private const string KillIfCannotCloseSettingName = "KillIfCannotClose";

        /// <summary>
        /// The name of the setting exposed in this user control.
        /// </summary>
        private const string AskFirstSettingName = "AskFirst";

        /// <summary>
        /// The name of the setting exposed in this user control.
        /// </summary>
        private const string ProgramsToCloseSettingName = "ProgramsToClose";

        /// <summary>
        /// Backend field for <code>CloseThesePrograms</code> property.
        /// </summary>
        private bool closeThesePrograms;

        /// <summary>
        /// Backend field for <code>KillIfCannotClose</code> property.
        /// </summary>
        private bool killIfCannotClose;

        /// <summary>
        /// Backend field for <code>AskFirst</code> property.
        /// </summary>
        private bool askFirst;

        /// <summary>
        /// The list of programs to be closed.
        /// </summary>
        private IList<ProgramToClose> programs = new List<ProgramToClose>();

        /// <summary>
        /// Gets or sets a value indicating whether the programs included in <code>ProgramsToClose</code> should be closed while the user is giving
        /// a presentation.
        /// </summary>
        public bool CloseThesePrograms
        {
            get
            {
                return this.closeThesePrograms;
            }

            set
            {
                this.closeThesePrograms = value;
                if (!this.closeThesePrograms)
                {
                    this.KillIfCannotClose = false;
                }

                this.NotifyPropertyChanged("CloseThesePrograms");

                // Since CanAskFirst is readonly but its value depends on this property we need to fire this event manually.
                this.NotifyPropertyChanged("CanAskFirst");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether programs should be killed if cannot be closed.
        /// </summary>
        public bool KillIfCannotClose
        {
            get
            {
                return this.killIfCannotClose;
            }

            set
            {
                this.killIfCannotClose = value;
                if (!this.killIfCannotClose)
                {
                    this.AskFirst = false;
                }

                this.NotifyPropertyChanged("KillIfCannotClose");

                // Since CanAskFirst is readonly but its value depends on this property we need to fire this event manually.
                this.NotifyPropertyChanged("CanAskFirst");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the user should confirm before killing a program.
        /// </summary>
        public bool AskFirst
        {
            get
            {
                return this.askFirst;
            }

            set
            {
                this.askFirst = value;
                this.NotifyPropertyChanged("AskFirst");
            }
        }

        /// <summary>
        /// Gets a value indicating whether the property <code>AskFirst</code> can be modified or not.
        /// </summary>
        public bool CanAskFirst
        {
            get
            {
                return this.CloseThesePrograms && this.KillIfCannotClose;
            }
        }

        /// <summary>
        /// Gets the list of programs to close while the user is giving a presentation.
        /// </summary>
        public IList<ProgramToClose> Programs
        {
            get
            {
                return this.programs;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the user is giving a presentation.
        /// </summary>
        internal bool Presenting { get; set; }

        /// <summary>
        /// Load model state using the <code>SettingsManager</code>.
        /// </summary>
        internal void Load()
        {
            this.CloseThesePrograms = SettingsManager.Instance.GetValue(CloseTheseProgramsSettingName, false);
            this.KillIfCannotClose = SettingsManager.Instance.GetValue(KillIfCannotCloseSettingName, false);
            this.AskFirst = SettingsManager.Instance.GetValue(AskFirstSettingName, false);

            string programsToClose = SettingsManager.Instance.GetValue(ProgramsToCloseSettingName, String.Empty);
            foreach (string moduleFileName in programsToClose.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                this.Programs.Add(new ProgramToClose(moduleFileName));
            }
        }

        /// <summary>
        /// Saves model state using the <code>SettingsManager</code>.
        /// </summary>
        internal void Save()
        {
            SettingsManager.Instance.SetValue(CloseTheseProgramsSettingName, this.CloseThesePrograms);
            SettingsManager.Instance.SetValue(KillIfCannotCloseSettingName, this.KillIfCannotClose);
            SettingsManager.Instance.SetValue(AskFirstSettingName, this.AskFirst);
            SettingsManager.Instance.SetValue(ProgramsToCloseSettingName, this.GetCommaSeparatedListOfSelectedPrograms());
        }

        /// <summary>
        /// Returns items in the list of programs in a comma separated list.
        /// </summary>
        /// <returns>A comma separated list of programs.</returns>
        private string GetCommaSeparatedListOfSelectedPrograms()
        {
            StringBuilder sb = new StringBuilder();
            foreach (ProgramToClose program in this.programs)
            {
                sb.Append(program.ModuleFileName);
                sb.Append(",");
            }

            return sb.ToString();
        }
    }
}
